前幾篇介紹了 Vuex 管理資料狀態,以及在生命週期或導航守衛發送 API 的時機點,再次回到專案範例,目前已處理好顯示導覽列中的全部書單內容,我們接續完成其他導覽項目所需要的畫面資料。
action 發送 API 後將資料以 commit
呼叫 mutation
actions: {
async fetchBookList(context) {
const books = await GET();
context.commit("bookList", books);
},
},
mutation 將資料直送並賦值給 state
state: {
bookList: {},
},
mutations: {
bookList(state, books) {
state.bookList = books;
},
},
getters 取得 state 資料
方式一:從 state 拿取同一份資料,再各別進行資料處理
getters: {
allBooks: (state) => state.bookList.list,
discount30Books: (state) =>
state.bookList.list.filter(
(book) =>
0.7 <= book.sellPrice / book.originPrice &&
book.sellPrice / book.originPrice < 0.8
),
discount50Books: (state) =>
state.bookList.list.filter(
(book) =>
0.5 <= book.sellPrice / book.originPrice &&
book.sellPrice / book.originPrice < 0.6
),
ithelpBook: (state) =>
state.bookList.list.filter((book) => book.name.includes("鐵人賽")),
},
方式二:透過拿取其他 getters 再加工處理,當遇到重複的篩選條件也可合併為一個共用函式加以簡化
getters: {
allBooks: (state) => state.bookList.list,
discountBooks: (state, getters) => (min, max) =>
getters.allBooks.filter(
(book) =>
min <= book.sellPrice / book.originPrice &&
book.sellPrice / book.originPrice < max
),
discount30Books: (state, getters) => getters.discountBooks(0.7, 0.8),
discount50Books: (state, getters) => getters.discountBooks(0.5, 0.6),
ithelpBook: (state, getters) =>
getters["allBooks"].filter((book) => book.name.includes("鐵人賽")),
}
最後,在元件內的 computed 取用 getters 的資料
computed: {
books() {
return this.$store.getters["allBooks"];
},
},
以上算是發送 API 和資料處理的基本流程方向,但因應每個人的開發習慣多少還是會有差異。有些人的作法可能會根據資料的共用範圍決定處理資料的時間點:
目前的做法會是統一都在 getters 處理資料,因此在元件內只需單純取用 getter 即可,如此一來我將所有的複雜邏輯集中在 getters 做好管理,當資料有任何錯誤情形發生時,就不用再回想資料有沒有共用情形、當初是放在哪一邊處理邏輯等瑣碎問題,而來回在 getters 和 computed 之間檢查程式碼。
回到 Vuex 的開頭以 dispatch
呼叫 action,選擇在適合的導航守衛位置發送 API。
全域 beforeEach
發送 API:看似快速又方便,但是進入其他不需要書單資料的頁面時也會跟著發送 API。
router.beforeEach(async (to, from, next) => {
await store.dispatch("fetchBookList");
next();
});
路由 beforeEnter
發送 API:將導覽項目路由規劃成巢狀結構,直接在父層路由發送 API。
{
path: "/book",
redirect: { name: "All" },
component: MainPage,
beforeEnter: async (to, from, next) => {
await store.dispatch("fetchBookList");
next();
},
children: [
{
path: "all",
name: "All",
component: All,
},
... // 略
],
},
在頁面中新增顯示書單筆數。
切換導覽項目時,能更明顯確認不同頁面所串接的資料差異。
由於所有導覽項目頁面內的排版一致,因此可將排版另外包成一個元件,之後也會陸續介紹元件之間傳遞資料的方式。